//
//  MMGJoyStickView.m
//  MyApp
//
//  Created by Don on 2017/8/19.
//
//

#import "MMGJoyStickView.h"
#import <HWWeakTimer.h>
#import "UIImage+CacheViaName.h"
#import "UIView+PointConvert.h"
#import "CGPointExtension.h"
//
#define pi 3.14159265358979323846
#define degreesToRadian(x) (pi * x / 180.0)
#define radiansToDegrees(x) (180.0 * x / pi)

#define MMGJoystickDirectionUpdataTime (1/20)
static float kMMG_Joystick_Direction_Send_Sec = 0.1;//每隔100毫秒发送摇杆方向力度

@interface MMGJoyStickView ()<UIGestureRecognizerDelegate>

@property (nonatomic, assign) BOOL isFollowTouch;
@property (nonatomic, assign) BOOL isAutoHide;
@property (nonatomic, assign) BOOL isCanVisible;
@property (nonatomic, assign) BOOL hasAnimation;

@property (nonatomic, assign) BOOL isTouched;

@property (nonatomic, assign) float moveAreaRadius;
@property (nonatomic, assign) float radian;//弧度
@property (nonatomic, assign) float power;
@property (nonatomic, assign) CGPoint direction;
@property (nonatomic, assign) float activeRadius;
@property (nonatomic, assign) CGRect activeRect;
@property (nonatomic, assign) CGPoint centerPoint;

@property (nonatomic, weak) NSTimer *timer;
@property (nonatomic, assign)NSTimeInterval lastSendDirectionTime;

@property (nonatomic, strong) UIImageView *jsBallIMView;
@property (nonatomic, strong) UIImageView *jsDockIMView;

@property (nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer;
@property (nonatomic, strong) UITapGestureRecognizer *tapGestureRecognizer;
@end

@implementation MMGJoyStickView {
    dispatch_queue_t joyStickQueue;
}

- (instancetype)initJoyStickWithFrame:(CGRect)frame moveAreaRadius:(float)moveAreaRadius followTouch:(BOOL)isFollowTouch canVisible:(BOOL)isCanVisible autoHide:(BOOL)isAutoHide animation:(BOOL)animation {

    if ((self = [super initWithFrame:frame])) {
        
        self.moveAreaRadius = moveAreaRadius;
        
        self.isFollowTouch = isFollowTouch;
        self.isCanVisible = isCanVisible;
        self.isAutoHide = isAutoHide;
        self.hasAnimation = animation;
        
        
        if (!isCanVisible) {
            self.alpha = 0.25;
        }else {
            
            if (_isAutoHide) {
                self.alpha = 0.25;
            }
        }
        
        self.multipleTouchEnabled = NO;
//        [self addGestureRecognizer:self.panGestureRecognizer];
        self.centerPoint = ccp(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
        
        joyStickQueue = dispatch_queue_create("com.memego.joystick.queue", DISPATCH_QUEUE_CONCURRENT);
        
        self.lastSendDirectionTime = 0;
        
    }
    return self;

}

- (instancetype)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {

    }
    
    return self;
}
-(void)dealloc {
    if (_timer) {
        [_timer invalidate];
        _timer = nil;
    }
    
    DLog(@"%@ dealloc", NSStringFromClass([self class]));
}

#pragma mark - public methods
- (void)setJSBallWithImageName:(NSString *)ballName {
    UIImage *ball = [UIImage mmg_imageNamed:ballName];
    self.jsBallIMView.image = ball;
    self.jsBallIMView.frame = CGRectMake(0, 0, 64, 64);
    self.jsBallIMView.center = self.centerPoint;
}

//- (void)setJSStickWithImageName:(NSString *)stickName {
//    UIImage *stick = [UIImage mmg_imageNamed:stickName];
//    self.jsStickIMView.image = stick;
//}

- (void)setJSDockWithImageName:(NSString *)dockName {
    UIImage *dock = [UIImage mmg_imageNamed:dockName];
    self.jsDockIMView.image = dock;
    self.jsDockIMView.frame = self.bounds;
}

- (void)setHitAreaWithRadius:(double)radius {
    self.activeRadius = radius;
    self.activeRect = CGRectZero;

}
- (void)setHitAreaWithRange:(CGRect)range {
    self.activeRect = range;
    self.activeRadius = 0;

}

#pragma mark - private methods
- (void)startTimer {
    if (self.delegate && [self.delegate respondsToSelector:@selector(onMMGJoyStickActivated:)]) {
        [self.delegate onMMGJoyStickActivated:self];
        
        @autoreleasepool
        {
            _timer = [HWWeakTimer scheduledTimerWithTimeInterval:MMGJoystickDirectionUpdataTime block:^(id userInfo) {
                [self timerUpdate:_timer.timeInterval];
            } userInfo:nil repeats:YES];
            [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
            [[NSRunLoop currentRunLoop] run];
            [_timer fire];
        }
        
    }
}
- (void)stopTimer {

    if (self.delegate && [self.delegate respondsToSelector:@selector(onMMGJoyStickDeactivated:)]) {
        [self.delegate onMMGJoyStickDeactivated:self];
    }
    if (_timer) {
        [_timer invalidate];
        _timer = nil;

    }
}

- (void)timerUpdate:(float)f{
    [NSThread sleepForTimeInterval:kMMG_Joystick_Direction_Send_Sec];
    if (self.delegate && [self.delegate respondsToSelector:@selector(onMMGJoyStickUpdate:radian:directionPoint:power:)]) {
        [self.delegate onMMGJoyStickUpdate:self radian:self.radian directionPoint:self.direction power:self.power];
    }
}

- (void)touchBegan:(UITouch *)touch {
    
    self.isTouched = YES;
    
    if (self.isAutoHide && self.isCanVisible) {
        self.alpha = 1;
    }
    
    if (self.isFollowTouch) {
        CGPoint selfCenter = [touch locationInView:self.superview];
        self.center = selfCenter;
    }
    
    CGPoint touchPoint = [touch locationInView:self];
//    this->ball->stopAllActions();//remove all animation
    [self updateTouchPoint:touchPoint];
    
    dispatch_async(joyStickQueue, ^{ @autoreleasepool {
        [self startTimer];
    }});
    

}
- (void)resetTexturePosition {
    
    self.power = 0;
    self.radian = 0;
    self.direction = CGPointZero;
    
    if (!self.isAutoHide && self.isCanVisible && self.hasAnimation) {
        [UIView animateWithDuration:0.05
                              delay:0.
                            options:(UIViewAnimationCurveEaseInOut)
                        animations:^{
                            self.jsBallIMView.center = self.centerPoint;
                        }completion:^(BOOL finished){
                            DLog(@"Move to left done");
                        }];
    }else {
        self.jsBallIMView.center = self.centerPoint;
    }

}


- (BOOL)containsTouchLocation:(UITouch *)touch {
    
    CGPoint touchPoint = [touch locationInView:self];
//    touchPoint = [self convertToGL:touchPoint];
    if (self.activeRadius > 0) {
        CGPoint center = self.centerPoint;
        CGPoint touchPointInSuper = [touch locationInView:self];
        if (ccpDistance(touchPointInSuper, center) < self.activeRadius) {
            return YES;
        }
    }
    
    if (CGRectGetWidth(self.activeRect) > 0 && CGRectGetHeight(self.activeRect) > 0) {
        if (touchPoint.x > CGRectGetMinX(self.activeRect) && touchPoint.x < CGRectGetMaxX(self.activeRect) && touchPoint.y > CGRectGetMinY(self.activeRect) && touchPoint.y < CGRectGetMaxY(self.activeRect)) {
            return true;
        }
    }
    
    return NO;
}
- (void)updateTouchPoint:(CGPoint)touchPoint {
    
    dispatch_async(joyStickQueue, ^{ @autoreleasepool {
    
    
        CGPoint dtarget, dir;
        dir.x = touchPoint.x - self.centerPoint.x;
        dir.y = touchPoint.y - self.centerPoint.y;
        double len = sqrt(dir.x * dir.x + dir.y * dir.y);
        
        if(len < 20.0 && len > -20.0)
        {
            // center pos
            dtarget.x = 0.0;
            dtarget.y = 0.0;
            dir.x = 0;
            dir.y = 0;
        }
        else
        {
            dtarget = ccp(dir.x, dir.y);
            if(len>self.moveAreaRadius){
                double len_inv = (self.moveAreaRadius/len);
                dtarget.x *= len_inv;
                dtarget.y *= len_inv;
            }
            double len_inv = (1.0 / len);
            dir.x *= len_inv;
            dir.y *= len_inv;
        }
        [self stickMoveTo:dtarget];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            //摇杆返回参数
            self.radian = atan2(self.jsBallIMView.center.y - self.centerPoint.y, self.jsBallIMView.center.x - self.centerPoint.x);
            DLog(@"--------------------- radian %0.2f --------------------",radiansToDegrees(atan2(self.jsBallIMView.center.y - self.centerPoint.y, self.jsBallIMView.center.x - self.centerPoint.x)));
            self.power = ccpDistance(self.jsBallIMView.center, self.centerPoint)/(self.moveAreaRadius - CGRectGetWidth(self.jsBallIMView.frame));
            self.direction = ccp(cos(self.radian), sin(self.radian));
        });
    }});

}

- (void)stickMoveTo:(CGPoint)deltaToCenter
{
    dispatch_async(dispatch_get_main_queue(), ^{
        CGRect fr = self.jsBallIMView.frame;
        fr.origin.x = self.centerPoint.x-fr.size.width / 2 + deltaToCenter.x;
        fr.origin.y = self.centerPoint.y-fr.size.height/ 2 + deltaToCenter.y;
        self.jsBallIMView.frame = fr;
    });
    
}


#pragma mark - touch events
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    
    UITouch *touch = [touches anyObject];
    
    
    if (![self containsTouchLocation:touch]) {
        return;
    }
    
//    CGPoint touchPoint = [touch locationInView:self];
    //    touchPoint = [self convertToGL:touchPoint];
    [self touchBegan:touch];

}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint touchPoint = [touch locationInView:self];
    if (self.isTouched) {
        [self updateTouchPoint:touchPoint];
    }

}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    if (self.isTouched) {
        if (self.isAutoHide && self.isCanVisible) {
            self.alpha = 0.25;
        }
        
        self.isTouched = false;
        [self stopTimer];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            [self resetTexturePosition];
        });
        
    }
    


}

#pragma mark - layz init
- (UIImageView *)jsBallIMView {
    if (!_jsBallIMView) {
        _jsBallIMView = [[UIImageView alloc] init];
        
        [self insertSubview:_jsBallIMView aboveSubview:self.jsDockIMView];
    }
    return _jsBallIMView;
}
- (UIImageView *)jsDockIMView {
    if (!_jsDockIMView) {
        _jsDockIMView = [[UIImageView alloc] init];
        
        [self addSubview:_jsDockIMView];
    }
    return _jsDockIMView;
}


@end
